package service

import (
	"context"
	"net/http"
	"strconv"

	"gitee.com/liuxuezhan/ar-platform/base-common/headInfo"
	"gitee.com/liuxuezhan/ar-platform/base-common/pkg/xcode"

	config2 "gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/schema/config"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/service/config"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/pkg/xerrors"
	"github.com/jinzhu/copier"

	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/model/recharge"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/model/user"
	schemaUser "gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/schema/user"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/svc"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/pkg/utils"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/rpc"
	"github.com/bytedance/sonic"
	"github.com/zeromicro/go-zero/core/logc"
	"gorm.io/gorm"
)

type UserRechargeEvent struct {
	RechargeId    int64   `json:"rechargeId"`    // 充值ID
	UserId        int64   `json:"userId"`        // 会员ID
	Code          string  `json:"code"`          // 充值货币code
	Amount        float64 `json:"amount"`        // 充值金额
	RechargeTime  int64   `json:"rechargeTime"`  // 充值时间
	TypeId        int64   `json:"typeId"`        // 变动类型ID[对应config_inout_type表]
	TypeName      string  `json:"typeName"`      // 变动类型名称
	IsFirstCharge bool    `json:"isFirstCharge"` // 是否首充
	Business      string  `json:"business"`
	Ip            string  `json:"ip,omitempty"`           // @gotags: gorm:"type:varchar(255);not null;comment:用户IP"
	UserAgent     string  `json:"userAgent,omitempty"`    // @gotags: gorm:"type:varchar(255);not null;comment:浏览器userAgent"
	Fbc           string  `json:"fbc,omitempty"`          // @gotags: gorm:"type:varchar(4096);not null;comment:Fbc"
	Fbp           string  `json:"fbp,omitempty"`          // @gotags: gorm:"type:varchar(4096);not null;comment:Fbp"
	FacebookAdId  string  `json:"facebookAdId,omitempty"` // @gotags: gorm:"type:varchar(255);not null;comment:facebook广告id"
	SiteUrl       string  `json:"siteUrl,omitempty"`      // @gotags: gorm:"type:varchar(4096);not null;comment:站点地址"
	Email         string  `json:"email,omitempty"`        // @gotags: gorm:"type:varchar(4096);not null;comment:用户邮箱"
	Telephone     string  `json:"telephone,omitempty"`    // @gotags: gorm:"type:varchar(20);not null;comment:用户手机号"

}

// BalanceIncrease 余额增加
func BalanceIncrease(ctx context.Context, svcCtx *svc.ServiceContext, in *rpc.BalanceIncreaseRequest, Facebook *rpc.Facebook) (*rpc.BalanceIncreaseRespone, error) {
	ret := &rpc.BalanceIncreaseRespone{}

	if in.Amount <= 0 {
		logc.Info(ctx, "BalanceIncrease failed: in.Amount is zero")
		return ret, nil
	}

	inout, _ := config.NewInoutService(ctx, svcCtx).GetConfigType(in.TypeId)
	if inout == nil || inout.Id == 0 {
		logc.Error(ctx, "ErrPleaseConfigInoutType,inout", inout)
		return nil, xerrors.ErrPleaseConfigInoutType
	}
	if inout.TagType != config2.TagTypeAdd {
		return nil, xcode.New(http.StatusInternalServerError, "Type is not add balance.")
	}

	logc.Info(ctx, "BalanceIncrease:infoValidMark "+strconv.Itoa(int(inout.TypeId)))
	if inout.Value > 0 && inout.TypeId != config2.TYPE_MANNUAL_RECHARGE {
		in.ValidMark = in.Amount * inout.Value
	}
	logc.Info(ctx, "BalanceIncrease:infoValidMark "+strconv.Itoa(int(inout.TypeId))+","+strconv.Itoa(int(in.ValidMark)))
	var totalRecharge float64 = 0
	if _, ok := config2.TypeRecharge[inout.TypeId]; ok {
		totalRecharge = in.Amount
	}

	err := svcCtx.Db.Transaction(func(tx *gorm.DB) error {
		// 开启事务
		// 加余额
		userWallet, err := user.NewWalletModel(ctx, tx).
			AddBalance(in.UserId, in.Amount, &schemaUser.UserWallet{
				ValidMark:     in.ValidMark,
				TotalRecharge: totalRecharge,
			})
		if err != nil {
			return err
		}
		// 钱包日志
		userWalletLog, err := user.NewWalletLogModel(ctx, tx).Create(
			userWallet, schemaUser.TRANSFER_TYPE_IN, in.Amount,
			in.TypeId, in.SourceId, in.Description, in.OperatorId,
		)
		if err != nil {
			return err
		}
		ret = &rpc.BalanceIncreaseRespone{
			Id:           userWalletLog.ID,
			UserId:       userWalletLog.UserId,
			Amount:       userWalletLog.Amount,
			BalanceStart: userWalletLog.BalanceStart,
			BalanceEnd:   userWalletLog.BalanceEnd,
			TypeId:       userWalletLog.TypeID,
			TypeName:     userWalletLog.TypeName,
			SourceId:     userWalletLog.SourceId,
			Description:  userWalletLog.Description,
			OperatorId:   userWalletLog.OperatorId,
			CreatedAt:    userWalletLog.CreatedAt,
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	// 查询首充
	isFirstCharge := false
	firstOrder, err := recharge.NewRechargeOrderModel(ctx, svcCtx.Db).GetFirstRechargeOrder(ret.UserId)
	if err != nil {
		logc.Error(ctx, err)
	}
	if err == nil && firstOrder.OrderNo == "" {
		isFirstCharge = true
	}

	// 推送 kafka 消息
	rechargeId, _ := strconv.Atoi(ret.SourceId)
	msg := UserRechargeEvent{
		RechargeId:    int64(rechargeId),
		UserId:        ret.UserId,
		Amount:        ret.Amount,
		RechargeTime:  ret.CreatedAt,
		TypeId:        ret.TypeId,
		TypeName:      ret.TypeName,
		IsFirstCharge: isFirstCharge,
		Business:      headInfo.GetBusiness(ctx),
		Code:          in.Code,
	}
	if Facebook != nil {
		msg.Ip = Facebook.Ip
		msg.UserAgent = Facebook.UserAgent
		msg.Fbc = Facebook.Fbc
		msg.Fbp = Facebook.Fbp
		msg.FacebookAdId = Facebook.FacebookAdId
		msg.SiteUrl = Facebook.SiteUrl
		msg.Email = Facebook.Email
		msg.Telephone = Facebook.Telephone
	}
	s, _ := sonic.MarshalString(msg)
	if err = utils.SendKafkaMessage(svcCtx.Config.KafkaProvider.Topic, ctx, svcCtx, s); err != nil {
		logc.Error(ctx, err)
	}

	return ret, nil
}

// BalanceDecrease 余额扣减
func BalanceDecrease(ctx context.Context, svcCtx *svc.ServiceContext, in *rpc.BalanceDecreaseRequest) (*rpc.BalanceDecreaseRespone, error) {
	ret := &rpc.BalanceDecreaseRespone{}

	if in.Amount <= 0 {
		logc.Info(ctx, "BalanceDecrease failed: in.Amount is zero")
		return ret, nil
	}

	inout, _ := config.NewInoutService(ctx, svcCtx).GetConfigType(in.TypeId)
	if inout == nil || inout.Id == 0 {
		logc.Error(ctx, "ErrPleaseConfigInoutType,inout", inout)
		return nil, xerrors.ErrPleaseConfigInoutType
	}
	// 投注消费等额的消费量 && 人工提款处理消费量
	if inout.TypeId == config2.TYPE_GAME_BETTING {
		in.ValidConsume = in.Amount
	} else if in.TypeId != config2.TYPE_MANNUAL_RECHARGE {
		in.ValidConsume = 0
	}

	if inout.TagType != config2.TagTypeSub {
		return nil, xcode.New(http.StatusInternalServerError, "inoutType.TagTyp is not 2 .")
	}

	var totalWithdraw float64 = 0
	if in.TotalWithdraw <= 0 {
		if _, ok := config2.TypeWithdraw[inout.TypeId]; ok {
			totalWithdraw = in.Amount
		}
	} else {
		totalWithdraw = in.TotalWithdraw
	}

	err := svcCtx.Db.Transaction(func(tx *gorm.DB) error {
		// 减余额
		userWallet, err := user.NewWalletModel(ctx, tx).
			DeductBalance(in.UserId, in.Amount, &schemaUser.UserWallet{
				ValidConsume:  in.ValidConsume,
				TotalWithdraw: totalWithdraw,
			})
		if err != nil {
			return err
		}
		// 钱包日志
		if in.Amount != 0 {
			userWalletLog, err := user.NewWalletLogModel(ctx, tx).Create(
				userWallet, schemaUser.TRANSFER_TYPE_OUT, in.Amount,
				in.TypeId, in.SourceId, in.Description, in.OperatorId,
			)
			if err != nil {
				return err
			}
			ret = &rpc.BalanceDecreaseRespone{
				Id:           userWalletLog.ID,
				UserId:       userWalletLog.UserId,
				Amount:       userWalletLog.Amount,
				BalanceStart: userWalletLog.BalanceStart,
				BalanceEnd:   userWalletLog.BalanceEnd,
				TypeId:       userWalletLog.TypeID,
				TypeName:     userWalletLog.TypeName,
				SourceId:     userWalletLog.SourceId,
				Description:  userWalletLog.Description,
				OperatorId:   userWalletLog.OperatorId,
				CreatedAt:    userWalletLog.CreatedAt,
			}
		}
		// 提现和余额小于1后 ，打码限制清空
		if userWallet.Balance < 1 {
			if err = user.NewWalletModel(ctx, tx).ClearMarkConsume(userWallet.UserId); err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	// 推送 kafka 消息
	// if ret != nil {
	// 	s, _ := sonic.MarshalString(ret)
	// 	if err = utils.SendKafkaMessage(ctx, svcCtx, s); err != nil {
	// 		logc.Error(ctx, err)
	// 	}
	// }

	return ret, nil
}

// UserWallet 钱包列表
func UserWallet(ctx context.Context, svcCtx *svc.ServiceContext, in *rpc.UserWalletRequest) (*rpc.UserWalletResponse, error) {
	ret := &rpc.UserWalletResponse{}
	userWallets, err := user.NewWalletModel(ctx, svcCtx.Db).ListUserWallet(in.UserIds)
	if err != nil {
		return nil, err
	}
	_ = copier.Copy(&ret.DataList, userWallets)
	return ret, nil
}
